using ClickHouse.Ado;
using System;
using System.Data;

namespace Glpt.Data
{
    /// <summary>
    /// ClickHouse的数据库连接类
    /// </summary>
    public class ClickHouseInterFace : AbstractInterFace
    {
        private ClickHouseConnection connsql = null;
        private DataTable schemaTable = null;
        /// <summary>
        /// 初始化类的新实例
        /// </summary>
        /// <param name="dbitem">数据库项目</param>
        public ClickHouseInterFace(DbItem dbitem)
        {
            ClickHouseConnectionSettings settings = new ClickHouseConnectionSettings(ReplaceString(dbitem.GetConnString()));
            connsql = new ClickHouseConnection(settings);
        }

        /// <summary>
        /// 描述列元数据的DataTable
        /// </summary>
        public override DataTable SchemaTable
        {
            get
            {
                return schemaTable;
            }
        }

        /// <summary>
        /// 参数字符标志
        /// </summary>
        public override string ParamChar
        {
            get
            {
                return "@";
            }
        }

        /// <summary>
        /// 函数字符标志
        /// </summary>
        public override string FunctionChar
        {
            get
            {
                return "";
            }
        }

        /// <summary>
        /// 字符串连接标志
        /// </summary>
        public override string ConcatChar
        {
            get
            {
                return "+";
            }
        }

        /// <summary>
        /// 字段左字符
        /// </summary>
        public override string ColumnLeftChar
        {
            get
            {
                return "";
            }
        }

        /// <summary>
        /// 字段右字符
        /// </summary>
        public override string ColumnRightChar
        {
            get
            {
                return "";
            }
        }

        /// <summary>
        /// 获取SQL参数
        /// </summary>
        /// <param name="db_params">参数</param>
        /// <returns>SQL参数</returns>
        private ClickHouseParameter GetClickHouseParameter(DbParam db_params)
        {
            ClickHouseParameter sql_params = new ClickHouseParameter();
            sql_params.ParameterName = db_params.ParameterName;
            if (db_params.Value == null || db_params.Value is System.DBNull)
                sql_params.Value = DBNull.Value;
            else
                sql_params.Value = db_params.Value;
            if (db_params.DataType.Equals(DbParamType.Int))
                sql_params.DbType = DbType.Int32;
            else if (db_params.DataType.Equals(DbParamType.Double))
                sql_params.DbType = DbType.Double;
            else if (db_params.DataType.Equals(DbParamType.NVarChar))
                sql_params.DbType = DbType.String;
            else if (db_params.DataType.Equals(DbParamType.Char))
                sql_params.DbType = DbType.String;
            else if (db_params.DataType.Equals(DbParamType.DateTime))
                sql_params.DbType = DbType.DateTime;
            else if (db_params.DataType.Equals(DbParamType.Blob))
                sql_params.DbType = DbType.Object;
            else
                sql_params.DbType = DbType.String;
            return sql_params;
        }
        /// <summary>
        /// 获取SQL参数列表
        /// </summary>
        /// <param name="db_params">参数列表</param>
        /// <returns>SQL参数列表</returns>
        private ClickHouseParameter[] GetClickHouseParameter(DbParamCollection db_params)
        {
            ClickHouseParameter[] sql_params = new ClickHouseParameter[db_params.Count];
            for (int i = 0; i < db_params.Count; i++)
            {
                sql_params[i] = GetClickHouseParameter(db_params[i]);
            }
            return sql_params;
        }

        /// <summary>
        /// 是否有数据库事务
        /// </summary>
        /// <returns>是否</returns>
        public override bool HasTransaction()
        {
            return false;
        }

        /// <summary>
        /// 开始数据库事务
        /// </summary>
        /// <returns>是否成功</returns>
        public override bool BeginTransaction()
        {
            return false;
        }

        /// <summary>
        /// 提交数据库事务
        /// </summary>
        public override void Commit()
        {
        }

        /// <summary>
        /// 从挂起状态回滚事务
        /// </summary>
        public override void Rollback()
        {
        }

        /// <summary>
        /// 执行SQL查询
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <returns>结果集</returns>
        public override DataTable ExecSelect(string sql)
        {
            return ExecSelect(null, sql, null, false, -1);
        }

        /// <summary>
        /// 执行SQL查询
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="sql_params">SQL参数列表</param>
        /// <returns>结果集</returns>
        public override DataTable ExecSelect(string sql, DbParamCollection sql_params)
        {
            return ExecSelect(null, sql, sql_params, false, -1);
        }

        /// <summary>
        /// 执行SQL查询
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="sql_params">SQL参数列表</param>
        /// <param name="is_pro">是否是存储过程</param>
        /// <returns>结果集</returns>
        public override DataTable ExecSelect(string sql, DbParamCollection sql_params, bool is_pro)
        {
            return ExecSelect(null, sql, sql_params, is_pro, -1);
        }

        /// <summary>
        /// 执行SQL查询
        /// </summary>
        /// <param name="searchHostObj">发起执行的主体对象</param>
        /// <param name="sql">SQL语句</param>
        /// <param name="sql_params">SQL参数列表</param>
        /// <param name="is_pro">是否是存储过程</param>
        /// <param name="pageIndex">页码，从0开始，-1表示全部</param>
        /// <returns>结果集</returns>
        public override DataTable ExecSelect(object searchHostObj, string sql, DbParamCollection sql_params, bool is_pro, int pageIndex)
        {
            DataTable dt = new DataTable();
            try
            {
                if (connsql.State.Equals(ConnectionState.Closed)) connsql.Open();
                ClickHouseCommand cmdsql = new ClickHouseCommand(connsql, sql);
                cmdsql.CommandTimeout = this.CommandTimeout;
                if (is_pro) cmdsql.CommandType = CommandType.StoredProcedure;
                if (sql_params != null)
                {
                    ClickHouseParameter[] paramList = GetClickHouseParameter(sql_params);
                    foreach (ClickHouseParameter param in paramList)
                    {
                        cmdsql.Parameters.Add(param);
                    }
                }
                try
                {
                    using (IDataReader dataReader = cmdsql.ExecuteReader())
                    {
                        if (searchHostObj != null)
                            schemaTable = DataFuns.GetSchemaTable(dataReader);
                        string column_name = "";
                        for (int i = 0; i < dataReader.FieldCount; i++)
                        {
                            column_name = dataReader.GetName(i);
                            if (dt.Columns.Contains(column_name))
                            {
                                int iseq = 1;
                                while (dt.Columns.Contains(column_name + iseq.ToString()))
                                {
                                    iseq++;
                                }
                                column_name = column_name + iseq.ToString();
                            }
                            DataColumn dc = new DataColumn();
                            dc.DataType = dataReader.GetFieldType(i);
                            dc.ColumnName = column_name;
                            dt.Columns.Add(dc);
                        }
                        int irows = 0;
                        int page_size = ParamSet.PageRecordCout;
                        if (dataReader.NextResult())
                        {
                            while (dataReader.Read())
                            {
                                if (pageIndex >= 0 && irows < pageIndex * page_size)
                                {
                                    irows++;
                                    continue;
                                }
                                else if (pageIndex >= 0 && irows >= (pageIndex + 1) * page_size)
                                {
                                    //cmdsql.Cancel();
                                    break;
                                }
                                else
                                {
                                    irows++;
                                    DataRow dr = dt.NewRow();
                                    for (int i = 0; i < dataReader.FieldCount; i++)
                                    {
                                        dr[i] = dataReader.GetValue(i);
                                    }
                                    dt.Rows.Add(dr);
                                }
                            }
                        }
                        dt.AcceptChanges();
                    }
                }
                catch (ClickHouseException ex)
                {
                    if (ex.Code != 0)
                        throw;
                }
            }
            finally
            {
                if (connsql != null && !connsql.State.Equals(ConnectionState.Closed)) connsql.Close();
            }
            return dt;
        }

        /// <summary>
        /// 批量加载数据
        /// </summary>
        /// <param name="tablename">表名</param>
        /// <param name="map_mode">字段映射 0按名称 1按顺序</param>
        /// <param name="reader">数据流</param>
        /// <param name="batchsize">每一批次中的行数</param>
        public override void BulkCopy(string tablename, string map_mode, IDataReader reader, int batchsize)
        {
            throw new Exception("不支持DataReader方式");
        }

        /// <summary>
        /// 批量加载数据
        /// </summary>
        /// <param name="tablename">表名</param>
        /// <param name="map_mode">字段映射 0按名称 1按顺序</param>
        /// <param name="table">数据表</param>
        /// <param name="batchsize">每一批次中的行数</param>
        public override void BulkCopy(string tablename, string map_mode, DataTable table, int batchsize)
        {
            throw new Exception("不支持DataTable方式");
        }

        /// <summary>
        /// 批量加载数据
        /// </summary>
        /// <param name="tablename">表名</param>
        /// <param name="map_mode">字段映射 0按名称 1按顺序</param>
        /// <param name="rows">数据行</param>
        /// <param name="batchsize">每一批次中的行数</param>
        public override void BulkCopy(string tablename, string map_mode, DataRow[] rows, int batchsize)
        {
            throw new Exception("不支持DataRow方式");
        }

        /// <summary>
        /// 获取数据流
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <returns>数据流</returns>
        public override IDataReader ExecReader(string sql)
        {
            return ExecReader(sql, null, false);
        }

        /// <summary>
        /// 获取数据流
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="sql_params">SQL参数列表</param>
        /// <returns>数据流</returns>
        public override IDataReader ExecReader(string sql, DbParamCollection sql_params)
        {
            return ExecReader(sql, sql_params, false);
        }

        /// <summary>
        /// 获取数据流
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="sql_params">SQL参数列表</param>
        /// <param name="is_pro">是否是存储过程</param>
        /// <returns>数据流</returns>
        public override IDataReader ExecReader(string sql, DbParamCollection sql_params, bool is_pro)
        {
            try
            {
                if (connsql.State.Equals(ConnectionState.Closed)) connsql.Open();
                ClickHouseCommand cmdsql = new ClickHouseCommand(connsql, sql);
                cmdsql.CommandTimeout = this.CommandTimeout;
                if (is_pro) cmdsql.CommandType = CommandType.StoredProcedure;
                if (sql_params != null)
                {
                    ClickHouseParameter[] paramList = GetClickHouseParameter(sql_params);
                    foreach (ClickHouseParameter param in paramList)
                    {
                        cmdsql.Parameters.Add(param);
                    }
                }
                return cmdsql.ExecuteReader();
            }
            catch
            {
                if (connsql != null && !connsql.State.Equals(ConnectionState.Closed)) connsql.Close();
                throw;
            }
        }

        /// <summary>
        /// 执行SQL命令
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <returns>结果集</returns>
        public override int ExecUpdate(string sql)
        {
            return ExecUpdate(null, sql, null, false);
        }

        /// <summary>
        /// 执行SQL命令
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="sql_params">SQL参数列表</param>
        /// <returns>结果集</returns>
        public override int ExecUpdate(string sql, DbParamCollection sql_params)
        {
            return ExecUpdate(null, sql, sql_params, false);
        }

        /// <summary>
        /// 执行SQL命令
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="sql_params">SQL参数列表</param>
        /// <param name="is_pro">是否是存储过程</param>
        /// <returns>结果集</returns>
        public override int ExecUpdate(string sql, DbParamCollection sql_params, bool is_pro)
        {
            return ExecUpdate(null, sql, sql_params, is_pro);
        }

        /// <summary>
        /// 执行SQL命令
        /// </summary>
        /// <param name="searchHostObj">发起执行的主体对象</param>
        /// <param name="sql">SQL语句</param>
        /// <param name="sql_params">SQL参数列表</param>
        /// <param name="is_pro">是否是存储过程</param>
        /// <returns>结果集</returns>
        public override int ExecUpdate(object searchHostObj, string sql, DbParamCollection sql_params, bool is_pro)
        {
            try
            {
                if (connsql.State.Equals(ConnectionState.Closed)) connsql.Open();
                ClickHouseCommand cmdsql = new ClickHouseCommand(connsql, sql);
                cmdsql.CommandTimeout = this.CommandTimeout;
                if (is_pro) cmdsql.CommandType = CommandType.StoredProcedure;
                if (sql_params != null)
                {
                    ClickHouseParameter[] paramList = GetClickHouseParameter(sql_params);
                    foreach (ClickHouseParameter param in paramList)
                    {
                        cmdsql.Parameters.Add(param);
                    }
                }
                int ret = cmdsql.ExecuteNonQuery();
                return ret;
            }
            finally
            {
                if (connsql != null && !connsql.State.Equals(ConnectionState.Closed)) connsql.Close();
            }
        }

        /// <summary>
        /// 执行与释放或重置非托管资源相关的应用程序定义的任务
        /// </summary>
        public override void Dispose()
        {
            connsql = null;
        }
    }
}
